home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / flash-0.4.3 / lib / shape.cc < prev    next >
C/C++ Source or Header  |  1999-01-01  |  20KB  |  929 lines

  1. /////////////////////////////////////////////////////////////
  2. // Flash Plugin and Player
  3. // Copyright (C) 1998,1999 Olivier Debon
  4. // 
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. // 
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. // 
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18. // 
  19. ///////////////////////////////////////////////////////////////
  20. //  Author : Olivier Debon  <odebon@club-internet.fr>
  21. //
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include "swf.h"
  26. #include "shape.h"
  27. #include "bitmap.h"
  28. #include "graphic.h"
  29.  
  30. static char *rcsid = "$Id: shape.cc,v 1.27 1999/01/31 20:22:39 olivier Exp $";
  31.  
  32. #define PRINT 0
  33.  
  34. #define ABS(v) ((v) < 0 ? -(v) : (v))
  35.  
  36. static void bezierBuildPoints (  SPoint * &curPoint,
  37.                  int subdivisions,
  38.                  long a1X, long a1Y,
  39.                  long cX, long cY,
  40.                  long a2X, long a2Y);
  41.  
  42. static void freeSegments(Segment **segs, long n);
  43.  
  44. static void addSegment(Segment **segs, long height,
  45.                FillStyleDef *f0, FillStyleDef *f1,
  46.                long x1, long y1, long x2,long y2,
  47.                int aa);
  48.  
  49. static void renderScanLine(GraphicDevice *gd, long y, Segment *curSegs);
  50.  
  51. static void renderHitTestLine(GraphicDevice *gd, unsigned char id, long y, Segment *curSegs);
  52.  
  53. static void prepareStyles(GraphicDevice *gd, Matrix *matrix, Cxform *cxform, FillStyleDef *f, long n);
  54.  
  55. static void clearStyles(GraphicDevice *gd, FillStyleDef *f, long n);
  56.  
  57. // Constructor
  58.  
  59. Shape::Shape(long id, int level) : Character(ShapeType, id)
  60. {
  61.     defLevel = level;
  62.  
  63.     fillStyles = 0;
  64.     nbFillStyles = 0;
  65.  
  66.     lineStyles = 0;
  67.     nbLineStyles = 0;
  68.  
  69.     shapeRecords = 0;
  70.  
  71.     path = 0;
  72.     nbPath = 0;
  73.  
  74.     defaultFillStyle.type = f_Solid;
  75.     defaultFillStyle.color.red = 0;
  76.     defaultFillStyle.color.green = 0;
  77.     defaultFillStyle.color.blue = 0;
  78.  
  79.     defaultLineStyle.width = 0;
  80.  
  81.     // This is to force a first update
  82.     lastMat.a = 0;
  83.     lastMat.d = 0;
  84. }
  85.  
  86. Shape::~Shape()
  87. {
  88.     ShapeRecord     *cur,*del;
  89.  
  90.     delete fillStyles;
  91.     delete lineStyles;
  92.  
  93.     for(cur = shapeRecords; cur;)
  94.     {
  95.         del = cur;
  96.         delete del->newFillStyles;
  97.         delete del->newLineStyles;
  98.         cur = cur->next;
  99.         delete del;
  100.     }
  101.  
  102.     if (path) {
  103.         long n;
  104.         SPoint *point,*del;
  105.  
  106.         for(n=0; n<nbPath; n++) {
  107.             for(point = path[n].path; point; ) {
  108.                 del = point;
  109.                 point = point->next;
  110.                 delete del;
  111.             }
  112.         }
  113.         delete path;
  114.     }
  115. }
  116.  
  117. void
  118. Shape::setBoundingBox(Rect rect)
  119. {
  120.     boundary = rect;
  121. }
  122.  
  123. Rect
  124. Shape::getBoundingBox()
  125. {
  126.     return boundary;
  127. }
  128.  
  129. void
  130. Shape::setFillStyleDefs(FillStyleDef *defs,long n)
  131. {
  132.     fillStyles = defs;
  133.     nbFillStyles = n;
  134. }
  135.  
  136. void
  137. Shape::setLineStyleDefs(LineStyleDef *defs,long n)
  138. {
  139.     lineStyles = defs;
  140.     nbLineStyles = n;
  141. }
  142.  
  143. void
  144. Shape::addShapeRecord(ShapeRecord  *sr)
  145. {
  146.     static ShapeRecord *last;
  147.     sr->next = 0;
  148.  
  149.     if (shapeRecords == 0) {
  150.         shapeRecords = sr;
  151.     } else {
  152.         last->next = sr;
  153.     }
  154.     last = sr;
  155. }
  156.  
  157. int
  158. Shape::execute(GraphicDevice *gd, Matrix *matrix, Cxform *cxform)
  159. {
  160.     //printf("TagId = %d\n", getTagId()); //if (getTagId() != 11) return 0;
  161.  
  162.     if (cxform) {
  163.         defaultFillStyle.color = cxform->getColor(gd->getForegroundColor());
  164.     } else {
  165.         defaultFillStyle.color = gd->getForegroundColor();
  166.     }
  167.     defaultFillStyle.color.pixel = gd->allocColor(defaultFillStyle.color);
  168.     doShape(gd, matrix, cxform, ShapeDraw, 0);
  169.     return 0;
  170. }
  171.  
  172. void
  173. Shape::getRegion(GraphicDevice *gd, Matrix *matrix, unsigned char id)
  174. {
  175.     doShape(gd, matrix,0, ShapeGetRegion, id);
  176. }
  177.  
  178. static
  179. SPoint *newPath(Path * &path, long &nbPath,
  180.         LineStyleDef *curLineStyle, long curNbLineStyles,
  181.         FillStyleDef *curFillStyle, long curNbFillStyles,
  182.         LineStyleDef *l,
  183.         FillStyleDef *f0,
  184.         FillStyleDef *f1,
  185.         long x, long y
  186.         )
  187. {
  188.     SPoint *point;
  189.  
  190.     if (path == 0) {
  191.         nbPath = 1;
  192.         path = (Path *)malloc(sizeof(Path));
  193.     } else {
  194.         nbPath++;
  195.         path = (Path *)realloc(path,nbPath*sizeof(Path));
  196.     }
  197.  
  198.     path[nbPath-1].lineStyles = curLineStyle;
  199.     path[nbPath-1].nbLineStyles = curNbLineStyles;
  200.     path[nbPath-1].fillStyles = curFillStyle;
  201.     path[nbPath-1].nbFillStyles = curNbFillStyles;
  202.  
  203.     point = new SPoint(x,y,f0,f1,l);
  204.  
  205.     path[nbPath-1].path = point;
  206.  
  207.     return point;
  208. }
  209.  
  210. void
  211. Shape::buildShape()
  212. {
  213.     LineStyleDef *curLineStyle;
  214.     long curNbLineStyles;
  215.     FillStyleDef *curFillStyle;
  216.     long curNbFillStyles;
  217.     LineStyleDef *l;
  218.     FillStyleDef *f0;
  219.     FillStyleDef *f1;
  220.     ShapeRecord *sr;
  221.     SPoint *curPoint;
  222.     long lastX,lastY;
  223.  
  224.     curLineStyle = lineStyles;
  225.     curNbLineStyles = nbLineStyles;
  226.     curFillStyle = fillStyles;
  227.     curNbFillStyles = nbFillStyles;
  228.     l = 0;
  229.     f0 = 0;
  230.     f1 = 0;
  231.     path = 0;
  232.     nbPath = 0;
  233.     curPoint = 0;
  234.     lastX = 0;
  235.     lastY = 0;
  236.  
  237.     for(sr = shapeRecords; sr; sr = sr->next)
  238.     {
  239.         switch (sr->type)
  240.         {
  241.             case shapeNonEdge:
  242.                 if (sr->flags & flagsNewStyles) {
  243.                     curFillStyle = sr->newFillStyles;
  244.                     curNbFillStyles = sr->nbNewFillStyles;
  245.                     curLineStyle = sr->newLineStyles;
  246.                     curNbLineStyles = sr->nbNewLineStyles;
  247.                 }
  248.                 if (sr->flags & flagsFill0) {
  249.                     if (sr->fillStyle0) {
  250.                         if (curFillStyle) {
  251.                             f0 = &curFillStyle[sr->fillStyle0-1];
  252.                         } else {
  253.                             f0 = &defaultFillStyle;
  254.                         }
  255.                     } else {
  256.                         f0 = 0;
  257.                     }
  258.                     if (curPoint) curPoint->f0 = f0;
  259.                 }
  260.                 if (sr->flags & flagsFill1) {
  261.                     if (sr->fillStyle1) {
  262.                         if (curFillStyle) {
  263.                             f1 = &curFillStyle[sr->fillStyle1-1];
  264.                         } else {
  265.                             f1 = &defaultFillStyle;
  266.                         }
  267.                     } else {
  268.                         f1 = 0;
  269.                     }
  270.                     if (curPoint) curPoint->f1 = f1;
  271.                 }
  272.                 if (sr->flags & flagsLine) {
  273.                     if (sr->lineStyle) {
  274.                         l = &curLineStyle[sr->lineStyle-1];
  275.                     } else {
  276.                         l = 0;
  277.                     }
  278.                     if (curPoint) curPoint->l = l;
  279.                 }
  280.                 if (sr->flags & flagsMoveTo) {
  281.  
  282.                     curPoint = newPath(path, nbPath, curLineStyle, curNbLineStyles,
  283.                                curFillStyle, curNbFillStyles,
  284.                                l, f0, f1, sr->x, sr->y);
  285.  
  286.                     lastX = sr->x;
  287.                     lastY = sr->y;
  288.  
  289. #if PRINT
  290.                     printf("---------\nX,Y    = %4d,%4d\n", sr->x/20, sr->y/20);
  291. #endif
  292.                 }
  293.                 break;
  294.             case shapeCurve:
  295.                 // Handle Bezier Curves !!!
  296.                 if (curPoint == 0) {
  297.                     curPoint = newPath(path, nbPath, curLineStyle, curNbLineStyles,
  298.                                curFillStyle, curNbFillStyles,
  299.                                l, f0, f1, 0, 0);
  300.                 }
  301.  
  302.                 {
  303.                     long newX,newY,ctrlX,ctrlY;
  304.  
  305.                     ctrlX = lastX+sr->ctrlX;
  306.                     ctrlY = lastY+sr->ctrlY;
  307.                     newX = ctrlX+sr->anchorX;
  308.                     newY = ctrlY+sr->anchorY;
  309.  
  310.                     bezierBuildPoints(curPoint, 3,
  311.                              lastX<<8,lastY<<8,
  312.                              ctrlX<<8,ctrlY<<8,
  313.                              newX<<8,newY<<8);
  314.  
  315.                     lastX = newX;
  316.                     lastY = newY;
  317.  
  318.                     // Add the last anchor
  319.                     curPoint->next = new SPoint(lastX, lastY, f0, f1, l);
  320.                     curPoint = curPoint->next;
  321. #if PRINT
  322.                     printf("aX,aY  = %4d,%4d   %4d,%4d\n", lastX/20, lastY/20, ctrlX/20, ctrlY/20);
  323. #endif
  324.                 }
  325.                 break;
  326.             case shapeLine:
  327.                 if (curPoint == 0) {
  328.                     curPoint = newPath(path, nbPath, curLineStyle, curNbLineStyles,
  329.                                curFillStyle, curNbFillStyles,
  330.                                l, f0, f1, 0, 0);
  331.                 }
  332.  
  333.                 lastX += sr->dX;
  334.                 lastY += sr->dY;
  335.  
  336.                 curPoint->next = new SPoint(lastX, lastY, f0, f1, l);
  337.                 curPoint = curPoint->next;
  338. #if PRINT
  339.                 printf(" X, Y  = %4d,%4d\n", lastX/20, lastY/20);
  340. #endif
  341.                 break;
  342.         }
  343.     }
  344. }
  345.  
  346. static void
  347. freeSegments(Segment **segs, long n)
  348. {
  349.     long i;
  350.  
  351.     for(i=0; i < n; i++)
  352.     {
  353.         Segment *seg, *next;
  354.  
  355.         for(seg = segs[i]; seg; seg = next)
  356.         {
  357.             next = seg->next;
  358.             free(seg);
  359.         }
  360.         segs[i] = 0;
  361.     }
  362. }
  363.  
  364. static void
  365. addSegment(Segment **segs, long height, FillStyleDef *f0,  FillStyleDef *f1, long x1, long y1, long x2,long y2, int aa)
  366. {
  367.     Segment *seg;
  368.     long Y20;
  369.  
  370.     seg = (Segment *)malloc(sizeof(struct Segment));
  371.     seg->next = 0;
  372.     seg->nextValid = 0;
  373.     seg->aa = aa;
  374.  
  375.     if (y1 < y2) {
  376.         seg->ymin = y1;
  377.         seg->ymax = y2;
  378.         seg->x1 = x1;
  379.         seg->x2 = x2;
  380.         seg->fs[0] = f1;
  381.         seg->fs[1] = f0;
  382.     } else {
  383.         seg->ymin = y2;
  384.         seg->ymax = y1;
  385.         seg->x1 = x2;
  386.         seg->x2 = x1;
  387.         seg->fs[0] = f0;
  388.         seg->fs[1] = f1;
  389.     }
  390.     seg->X = seg->x1 << 16;
  391.     seg->dX = ((seg->x2 - seg->x1)<<16)/(seg->ymax-seg->ymin);
  392.  
  393.     if (seg->ymin >= height*20) {
  394.         free(seg);
  395.         return;
  396.     }
  397.  
  398.     if (seg->ymin < 0) {
  399.         seg->X += seg->dX * (-seg->ymin);
  400.         seg->ymin = 0;
  401.     }
  402.  
  403.     Y20 = (seg->ymin + 19)/20*20;
  404.     if (Y20 > seg->ymax) {
  405.         //printf("Elimine @ y = %d   ymin = %d, ymax = %d\n", Y20, seg->ymin, seg->ymax);
  406.         free(seg);
  407.         return;
  408.     }
  409.     seg->X += seg->dX * (Y20-seg->ymin);
  410.  
  411.     Y20 /= 20;
  412.  
  413.     if (segs[Y20] == 0) {
  414.         segs[Y20] = seg;
  415.     } else {
  416.         Segment *s,*prev;
  417.  
  418.         prev = 0;
  419.         for(s = segs[Y20]; s; prev = s, s = s->next) {
  420.             if (s->X > seg->X) {
  421.                 if (prev) {
  422.                     prev->next = seg;
  423.                     seg->next = s;
  424.                 } else {
  425.                     seg->next = segs[Y20];
  426.                     segs[Y20] = seg;
  427.                 }
  428.                 break;
  429.             }
  430.         }
  431.         if (s == 0) {
  432.             prev->next = seg;
  433.             seg->next = s;
  434.         }
  435.     }
  436. }
  437.  
  438. static void
  439. printSeg(Segment *seg)
  440. {
  441.     /*
  442.     printf("Seg %08x : X = %5d, Ft = %d, Cl = %2x/%2x/%2x, Cr = %2x/%2x/%2x, x1=%5d, x2=%5d, ymin=%5d, ymax=%5d\n", seg,
  443.         seg->X>>16,
  444.         seg->right ? seg->right->type: -1,
  445.         seg->left ? seg->left->color.red : -1,
  446.         seg->left ? seg->left->color.green : -1,
  447.         seg->left ? seg->left->color.blue : -1,
  448.         seg->right ? seg->right->color.red : -1,
  449.         seg->right ? seg->right->color.green : -1,
  450.         seg->right ? seg->right->color.blue : -1,
  451.         seg->x1, seg->x2, seg->ymin, seg->ymax);
  452.     */
  453. }
  454.  
  455. static void
  456. renderScanLine(GraphicDevice *gd, long y, Segment *curSegs)
  457. {
  458.     Segment *seg;
  459.     long width;
  460.     int fi = 1;
  461.  
  462.     width = gd->getWidth() * 20;
  463.  
  464.     if (curSegs && curSegs->fs[0] && curSegs->fs[1] == 0) {
  465.         fi = 0;
  466.     }
  467.     for(seg = curSegs; seg && seg->nextValid; seg = seg->nextValid)
  468.     {
  469.         if (seg->nextValid->X <0) continue;
  470.         if ((seg->X>>16) > width) break;
  471.         if (seg->fs[fi]) {
  472.             switch (seg->fs[fi]->type) {
  473.                 case f_Solid:
  474.                     gd->fillLine(seg->fs[fi]->color.pixel, y, seg->X>>16, seg->nextValid->X>>16, seg->aa);
  475.                     break;
  476.                 case f_TiledBitmap:
  477.                 case f_clippedBitmap:
  478.                     gd->fillLine(seg->fs[fi]->pix, seg->fs[fi]->xOffset, seg->fs[fi]->yOffset, y, seg->X>>16, seg->nextValid->X>>16);
  479.                     break;
  480.                 case f_LinearGradient:
  481.                     gd->fillLine(&seg->fs[fi]->gradient, y, seg->X>>16, seg->nextValid->X>>16);
  482.                     break;
  483.                 case f_RadialGradient:
  484.                     gd->fillLineRG(&seg->fs[fi]->gradient, y, seg->X>>16, seg->nextValid->X>>16);
  485.                     break;
  486.             }
  487.         }
  488.     }
  489. }
  490.  
  491. static void
  492. renderHitTestLine(GraphicDevice *gd, unsigned char id, long y, Segment *curSegs)
  493. {
  494.     Segment *seg;
  495.  
  496.     for(seg = curSegs; seg && seg->nextValid; seg = seg->nextValid)
  497.     {
  498.         if (seg->fs[1]) {
  499.             if (seg->nextValid->X >= seg->X) {
  500.                 gd->fillHitTestLine(id, y, seg->X>>16, seg->nextValid->X>>16);
  501.             }
  502.         }
  503.     }
  504. }
  505.  
  506. void
  507. Shape::drawLines(GraphicDevice *gd, Matrix *matrix, Cxform *cxform, long pStart, long pEnd)
  508. {
  509.     SPoint *point;
  510.     long n;
  511.     long w = 20;
  512.     LineStyleDef *ls;
  513.  
  514.     // Drawlines
  515.     ls = 0;
  516.     for(n=pStart; n <= pEnd && n < nbPath; n++) {
  517.         for(point = path[n].path; point->next; point = point->next) {
  518.             if (point->l != ls) {
  519.                 if (point->l) {
  520.                     if (cxform) {
  521.                         gd->setForegroundColor(cxform->getColor(point->l->color));
  522.                     } else {
  523.                         gd->setForegroundColor(point->l->color);
  524.                     }
  525.                     w = ABS((long)(matrix->a*point->l->width));
  526.                 }
  527.                 ls = point->l;
  528.             }
  529.             if (ls) {
  530.                 gd->drawLine(point->X,point->Y,point->next->X,point->next->Y,w);
  531.             }
  532.         }
  533.     }
  534.     gd->synchronize();
  535. }
  536.  
  537. static void
  538. prepareStyles(GraphicDevice *gd, Matrix *matrix, Cxform *cxform, FillStyleDef *f, long n)
  539. {
  540.     long fs;
  541.  
  542.     for(fs = 0; fs < n; fs++)
  543.     {
  544.         switch (f[fs].type)
  545.         {
  546.             case f_Solid:
  547.                 if (cxform) {
  548.                     f[fs].color.pixel = gd->allocColor(cxform->getColor(f[fs].color));
  549.                 } else {
  550.                     f[fs].color.pixel = gd->allocColor(f[fs].color);
  551.                 }
  552.                 break;
  553.             case f_LinearGradient:
  554.             case f_RadialGradient:
  555.                 {
  556.                     Matrix mat;
  557.                     int  n,r,l;
  558.                     long red, green, blue;
  559.                     long dRed, dGreen, dBlue;
  560.                     long min,max;
  561.  
  562.                     mat = *(matrix) * f[fs].matrix;
  563.                     // Compute inverted matrix
  564.                     f[fs].gradient.imat = mat.invert();
  565.                     // Store translation vector
  566.                     f[fs].gradient.xOffset = f[fs].gradient.imat.tx;
  567.                     f[fs].gradient.yOffset = f[fs].gradient.imat.ty;
  568.                     // Reset translation in inverted matrix
  569.                     f[fs].gradient.imat.tx = 0;
  570.                     f[fs].gradient.imat.ty = 0;
  571.                     // Build a 256 color ramp
  572.                     f[fs].gradient.ramp = new Color[256];
  573.                     // Store min and max
  574.                     min = f[fs].gradient.ratio[0];
  575.                     max = f[fs].gradient.ratio[f[fs].gradient.nbGradients-1];
  576.                     for(r=0; r < f[fs].gradient.nbGradients-1; r++)
  577.                     {
  578.                         Color start,end;
  579.  
  580.                         l = f[fs].gradient.ratio[r+1]-f[fs].gradient.ratio[r];
  581.                         if (l == 0) continue;
  582.  
  583.                         if (cxform) {
  584.                             start = cxform->getColor(f[fs].gradient.color[r]);
  585.                             end   = cxform->getColor(f[fs].gradient.color[r+1]);
  586.                         } else {
  587.                             start = f[fs].gradient.color[r];
  588.                             end   = f[fs].gradient.color[r+1];
  589.                         }
  590.  
  591.                         dRed   = end.red - start.red;
  592.                         dGreen = end.green - start.green;
  593.                         dBlue  = end.blue - start.blue;
  594.  
  595.                         dRed   = (dRed<<16)/l;
  596.                         dGreen = (dGreen<<16)/l;
  597.                         dBlue  = (dBlue<<16)/l;
  598.  
  599.                         red   = start.red <<16;
  600.                         green = start.green <<16;
  601.                         blue  = start.blue <<16;
  602.  
  603.                         for (n=f[fs].gradient.ratio[r]; n<=f[fs].gradient.ratio[r+1]; n++) {
  604.                             f[fs].gradient.ramp[n].red = red>>16;
  605.                             f[fs].gradient.ramp[n].green = green>>16;
  606.                             f[fs].gradient.ramp[n].blue = blue>>16;
  607.  
  608.                             f[fs].gradient.ramp[n].pixel = gd->allocColor(f[fs].gradient.ramp[n]);
  609.                             red += dRed;
  610.                             green += dGreen;
  611.                             blue += dBlue;
  612.                         }
  613.                     }
  614.                     for(n=0; n<min; n++) {
  615.                         f[fs].gradient.ramp[n].pixel = f[fs].gradient.ramp[min].pixel;
  616.                     }
  617.                     for(n=max; n<256; n++) {
  618.                         f[fs].gradient.ramp[n].pixel = f[fs].gradient.ramp[max].pixel;
  619.                     }
  620.                 }
  621.                 break;
  622.             case f_TiledBitmap:
  623.             case f_clippedBitmap:
  624.                 if (f[fs].bitmap) {
  625.                     Matrix mat;
  626.                     long xOffset, yOffset;
  627.  
  628.                     mat = *(matrix) * f[fs].matrix;
  629.  
  630.                     xOffset = mat.getX(0,0)/20;
  631.                     yOffset = mat.getY(0,0)/20;
  632.  
  633.                     if (f[fs].pix) {
  634.                         gd->destroySwfPix(f[fs].pix);
  635.                     }
  636.                     f[fs].pix = f[fs].bitmap->getImage(gd, &mat, cxform);
  637.                     f[fs].xOffset = xOffset;
  638.                     f[fs].yOffset = yOffset;
  639.                 }
  640.                 break;
  641.         }
  642.     }
  643. }
  644.  
  645. static void
  646. clearStyles(GraphicDevice *gd, FillStyleDef *f, long n)
  647. {
  648.     long fs;
  649.  
  650.     for(fs = 0; fs < n; fs++)
  651.     {
  652.         switch (f[fs].type)
  653.         {
  654.             case f_Solid:
  655.                 break;
  656.             case f_LinearGradient:
  657.             case f_RadialGradient:
  658.                 if (f[fs].gradient.ramp) {
  659.                     delete f[fs].gradient.ramp;
  660.                 }
  661.                 break;
  662.             case f_TiledBitmap:
  663.             case f_clippedBitmap:
  664.                 if (f[fs].bitmap) {
  665.                     if (f[fs].pix) {
  666.                         gd->destroySwfPix(f[fs].pix);
  667.                         f[fs].pix = 0;
  668.                     }
  669.                 }
  670.                 break;
  671.         }
  672.     }
  673. }
  674.  
  675. void
  676. Shape::buildSegmentList(Segment **segs, int height, long &n, Matrix *mat, int update, int reverse)
  677. {
  678.     SPoint        *point;
  679.     long         x1,y1,x2,y2;
  680.  
  681.     if (update) {
  682.         for(; n < nbPath; n++) {
  683.             int first;
  684.             long lastX,lastY;
  685.  
  686.             if (path[n].path->next == 0) {
  687.                 break;
  688.             }
  689.  
  690.             first = 1;
  691.             for(point = path[n].path; point->next; point = point->next) {
  692.                 if (first) {
  693.                     y1 = point->Y = mat->getY(point->x, point->y);
  694.                     x1 = point->X = mat->getX(point->x, point->y);
  695.                     first = 0;
  696.                 } else {
  697.                     y1 = lastY;
  698.                     x1 = lastX;
  699.                 }
  700.                 y2 = point->next->Y = mat->getY(point->next->x, point->next->y);
  701.                 x2 = point->next->X = mat->getX(point->next->x, point->next->y);
  702.                 lastX = x2;
  703.                 lastY = y2;
  704.                 if (y1 == y2) continue;
  705.                 if (!reverse) {
  706.                     addSegment(segs,height,point->f0, point->f1, x1,y1,x2,y2, point->l ? 0:1);
  707.                 } else {
  708.                     addSegment(segs,height,point->f1, point->f0, x1,y1,x2,y2, point->l ? 0:1);
  709.                 }
  710.             }
  711.         }
  712.     } else {
  713.         for(; n < nbPath; n++) {
  714.             if (path[n].path->next == 0) {
  715.                 break;
  716.             }
  717.  
  718.             for(point = path[n].path; point->next; point = point->next) {
  719.                 y1 = point->Y;
  720.                 x1 = point->X;
  721.                 y2 = point->next->Y;
  722.                 x2 = point->next->X;
  723.                 if (y1 == y2) continue;
  724.                 if (!reverse) {
  725.                     addSegment(segs,height,point->f0, point->f1, x1,y1,x2,y2, point->l ? 0:1);
  726.                 } else {
  727.                     addSegment(segs,height,point->f1, point->f0, x1,y1,x2,y2, point->l ? 0:1);
  728.                 }
  729.             }
  730.         }
  731.     }
  732. }
  733.  
  734. Segment *
  735. Shape::progressSegments(Segment * curSegs, long y)
  736. {
  737.     Segment *seg,*prev;
  738.  
  739.     // Update current segments
  740.     seg = curSegs;
  741.     prev = 0;
  742.     while(seg)
  743.     {
  744.         if (y*20 > seg->ymax) {
  745.             // Remove this segment, no more valid
  746.             if (prev) {
  747.                 prev->nextValid = seg->nextValid;
  748.             } else {
  749.                 curSegs = seg->nextValid;
  750.             }
  751.             seg = seg->nextValid;
  752.         } else {
  753.             seg->X += seg->dX * 20;
  754.             prev = seg;
  755.             seg = seg->nextValid;
  756.         }
  757.     }
  758.     return curSegs;
  759. }
  760.  
  761. Segment *
  762. Shape::newSegments(Segment *curSegs, Segment *newSegs)
  763. {
  764.     Segment *s,*seg,*prev;
  765.  
  766.     s = curSegs;
  767.     prev = 0;
  768.  
  769.     // Check for new segments
  770.     for (seg = newSegs; seg; seg=seg->next)
  771.     {
  772.         // Place it at the correct position according to X
  773.         if (curSegs == 0) {
  774.             curSegs = seg;
  775.             seg->nextValid = 0;
  776.         } else {
  777.             for(; s; prev = s, s = s->nextValid)
  778.             {
  779.                 if ( s->X > seg->X
  780.                 || ( (s->X == seg->X)
  781.                      && (
  782.                         (seg->x1 == s->x1 && seg->dX < s->dX)
  783.                         ||
  784.                         (seg->x2 == s->x2 && seg->dX > s->dX)
  785.                     )
  786.                    )
  787.                 ) {
  788.                     // Insert before s
  789.                     if (prev) {
  790.                         seg->nextValid = s;
  791.                         prev->nextValid = seg;
  792.                     } else {
  793.                         seg->nextValid = curSegs;
  794.                         curSegs = seg;
  795.                     }
  796.                     break;
  797.                 }
  798.             }
  799.             // Append at the end
  800.             if (s == 0) {
  801.                 prev->nextValid = seg;
  802.                 seg->nextValid = 0;
  803.             }
  804.         }
  805.  
  806.         s = seg;
  807.     }
  808.  
  809.     return curSegs;
  810. }
  811.  
  812. void
  813. Shape::doShape(GraphicDevice *gd, Matrix *matrix, Cxform *cxform, ShapeAction shapeAction, unsigned char id)
  814. {
  815.     long     n;
  816.     long     lastPath;
  817.     long     y;
  818.     long     height;
  819.     Segment **segs;    // Array of segments
  820.     Segment *curSegs;
  821.     Matrix     mat;
  822.     int     update;
  823.     int     reverse;
  824.  
  825.     mat = (*gd->adjust) * (*matrix);
  826.  
  827.     if (mat.a != lastMat.a
  828.     ||  mat.d != lastMat.d
  829.     ||  mat.b != lastMat.b
  830.     ||  mat.c != lastMat.c
  831.     ||  mat.tx != lastMat.tx
  832.     ||  mat.ty != lastMat.ty) {
  833.         update = 1;
  834.         lastMat = mat;
  835.     } else {
  836.         update = 0;
  837.     }
  838.  
  839.     height = gd->getHeight();
  840.  
  841.     n = 0;
  842.     lastPath = 0;
  843.     reverse = (mat.a * mat.d) < 0;
  844.  
  845.     segs = (Segment **)calloc(height+1, sizeof(Segment *));
  846.  
  847.     while (n<nbPath) {
  848.  
  849.         if (shapeAction == ShapeDraw) {
  850.             prepareStyles(gd, &mat, cxform, path[n].fillStyles, path[n].nbFillStyles);
  851.         }
  852.  
  853.         buildSegmentList(segs, height, n, &mat, update, reverse);
  854.  
  855.         // Foreach scanline
  856.         curSegs = 0;
  857.         for(y=0; y < height; y++)
  858.         {
  859.  
  860.             // Make X values progess and remove unuseful segments
  861.             curSegs = progressSegments(curSegs, y);
  862.  
  863.             // Add the new segment starting at the y position.
  864.             curSegs = newSegments(curSegs, segs[y]);
  865.  
  866.             // Render the scanline
  867.             if (shapeAction == ShapeDraw) {
  868.                 renderScanLine(gd, y, curSegs);
  869.                 
  870.                 //printf("Id %d  - Y = %d\n", getTagId(), y);
  871.                 /*
  872.                 if (debug) {
  873.                 gd->displayCanvas();
  874.                 getchar();
  875.                 }
  876.                 */
  877.             } else {
  878.                 renderHitTestLine(gd, id, y, curSegs);
  879.             }
  880.         }
  881.  
  882.         freeSegments(segs,height);
  883.  
  884.         if (shapeAction == ShapeDraw) {
  885.             drawLines(gd, &mat, cxform, lastPath, n-1);
  886.             clearStyles(gd, path[lastPath].fillStyles, path[lastPath].nbFillStyles);
  887.         }
  888.  
  889.         lastPath = n;
  890.  
  891.         n++;
  892.     }
  893.     free(segs);
  894. }
  895.  
  896. // This is based on Divide and Conquer algorithm.
  897.  
  898. static void
  899. bezierBuildPoints (  SPoint * &curPoint,
  900.              int subdivisions,
  901.              long a1X, long a1Y,
  902.              long cX, long cY,
  903.              long a2X, long a2Y)
  904. {
  905.     long c1X,c1Y;
  906.     long c2X,c2Y;
  907.     long X,Y;
  908.  
  909.     // Control point 1
  910.     c1X = (a1X+cX)/2;
  911.     c1Y = (a1Y+cY)/2;
  912.  
  913.     // Control point 2
  914.     c2X = (a2X+cX)/2;
  915.     c2Y = (a2Y+cY)/2;
  916.  
  917.     // New point
  918.     X = (c1X+c2X)/2;
  919.     Y = (c1Y+c2Y)/2;
  920.  
  921.     if (subdivisions == 1) {
  922.         curPoint->next = new SPoint((X+(1<<7))>>8, (Y+(1<<7))>>8, curPoint->f0, curPoint->f1, curPoint->l);
  923.         curPoint = curPoint->next;
  924.     } else {
  925.         bezierBuildPoints(curPoint, subdivisions-1, a1X, a1Y, c1X, c1Y, X, Y);
  926.         bezierBuildPoints(curPoint, subdivisions-1, X, Y, c2X, c2Y, a2X, a2Y);
  927.     }
  928. }
  929.